GLOBAL  read_msw,_lidt
GLOBAL  int_08_hand , int_09_hand , int_03_hand , int_04_hand ,  int_85_hand , int_86_hand ;,int_81_hand, int_80_hand,
GLOBAL	mascaraPIC1
GLOBAL  mascaraPIC2
GLOBAL  _Cli
GLOBAL  _Sti
GLOBAL  _Hlt
GLOBAL  debug
GLOBAL  ArmaStackFrame
GLOBAL  write
GLOBAL  ejecutar
GLOBAL  malloc
GLOBAL  outb
GLOBAL  inb
GLOBAL  _ini_puerto
GLOBAL  switch_manual
GLOBAL  _renice
GLOBAL  _kill
GLOBAL  _top
GLOBAL  _leo_reloj
GLOBAL  getChar
GLOBAL  shmGet
GLOBAL  shmAt
GLOBAL  shmLock
GLOBAL  shmUnlock


;Excepciones
GLOBAL div0_hand
GLOBAL bounds_hand
GLOBAL opCode_hand
GLOBAL snoPresent_hand
GLOBAL ssf_hand
GLOBAL generalPfault_hand
GLOBAL pageFault_hand


EXTERN  Div0
EXTERN	Bounds
EXTERN  opCode
EXTERN	SnoPresent
EXTERN  Stacksf
EXTERN  GpFault
EXTERN  PageFault
	

EXTERN  int_08
EXTERN  int_09
EXTERN  int_86
;EXTERN  int_81
EXTERN  int_serial
EXTERN  LoadESP
EXTERN  SaveESP
EXTERN  getVideo
EXTERN  scheduler
EXTERN  GetNextProcess
EXTERN  int_85
EXTERN  getBuffer
SECTION .data

video       equ 0xb8000

ejecutarCode    equ 1
killCode        equ 2
reniceCode      equ 3
topCode         equ 4
writeCode       equ 5
gcNBCode        equ 6
gcCode          equ 7
readCode        equ 8
mallocCode      equ 9
shmgetCode      equ 10
shmatCode       equ 11
shmlockCode     equ 12
shmUnlockCode   equ 13

SECTION .text


;-----------------------------------------------
div0_hand:				; Handler de excepxi�n "Divide by zero"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax                  
	call Div0                 
	mov al,20h			; Envio de EOI generico al PIC
	out 20h,al
	popf
	popa
	pop es
	pop ds
	
	iret

bounds_hand:			        ; Handler de excepci�n "BOUND range exceeded"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call Bounds
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	popf
	popa
	pop es
	pop ds
	iret

opCode_hand:                            ; Handler de excepci�n "Invalid opcode"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call opCode
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	pop ax
	popa
	pop ax
	pop ax
	iret

snoPresent_hand: 			; Handler de excepci�n "Segment not present"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call SnoPresent
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	popf
	popa
	pop ax
	pop ax
	iret

ssf_hand:				; Handler de excepci�n "Stack exception"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax                  
	call Stacksf
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	popf
	popa
	pop ax
	pop ax
	iret

generalPfault_hand:			; Handler de excepci�n "General protection exception"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call GpFault
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	popf
	popa
	pop ax
	pop ax
	iret


pageFault_hand:
        push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax                  
	call PageFault                 
	mov al,20h			; Envio de EOI generico al PIC
	out 20h,al
	popf
	popa
	pop es
	pop ds
        sti
	jmp $
	iret


_Cli:
	cli                     ; limpia flag de interrupciones
	ret

_Sti:

	sti			            ; habilita interrupciones por flag
	ret
_Hlt:
    hlt
    ret

mascaraPIC1:			    ; Escribe mascara del PIC 1
	push    ebp
    mov     ebp, esp
    mov     ax, [ss:ebp+8]  ; ax = mascara de 16 bits
    out     21h,al
    pop     ebp
    retn

mascaraPIC2:			    ; Escribe mascara del PIC 2
    push    ebp
    mov     ebp, esp
    mov     ax, [ss:ebp+8]  ; ax = mascara de 16 bits
    out     0A1h,al
    pop     ebp
    retn

read_msw:
    smsw    ax		    ; Obtiene la Machine Status Word
    retn

_lidt:				        ; Carga el IDTR
    push    ebp
    mov     ebp, esp
    push    ebx
    mov     ebx, [ss:ebp+6]     ; ds:bx = puntero a IDTR 
	rol     ebx,16		    	
	lidt    [ds:ebx]            ; carga IDTR
    pop     ebx
    pop     ebp
    retn

_leo_reloj:
	push	ecx ; Se salvan los registros
	push	edx
        push	ebx
	push	sp
	push	bp
	push   	si
	push	di
	push    ds
        push	es
	
	mov 	eax,00000000h
	mov 	al,00h
	out	70h,al
	in	al,71h
		
	pop	es
	pop	ds
	pop	di
	pop	si
	pop	bp
	pop	sp
	pop	ebx
	pop	edx
	pop	ecx
	ret

ArmaStackFrame:
    ; flags
    pushfd
    push ebp
    mov ebp, esp
    ; sp por parametros
    mov eax, [ebp+16]
    ; usar ese stack
    mov esp, eax
    ; funcion a ejecutar
    mov eax, [ebp+12]
    ; funcion cementerio
    mov edx, [ebp+20]
    ; push de 'la nueva ret'
    push edx
    ; seteo el bit de habilitar interrupciones
    mov ecx, 512
    ; push flags (solo me interesa habilitar int)
    push ecx
    ; para iret
    push cs
    push eax
    ; resto de los registros
    pusha
    ; devolver el nuevo esp
    mov eax, esp
    ; y restaurar el original
    mov esp, ebp
    ; restaurar flags y ebp
    pop ebp
    popfd
    retn

int_08_hand:
    cli
    pusha
    push esp
    call GetNextProcess
    ;call scheduler
    pop esp
    mov esp, eax
    mov al, 20h
    out 20h, al
    popa
    sti

    iret


; write coloca en ebx el file descriptor, en ecx la direccion del buffer
; a escribir y en edx la cantidad de caracteres que contiene el buffer.
write:
    push    ebp             ; arma stack frame
    mov     ebp, esp

    call    getVideo
    push    eax             ; guardo dir. de video
    pop     ebx             ; en ebx
    mov     eax, writeCode
    ;mov     ebx, video
    mov     ecx, [ebp+12]   ; segundo parametro, buffer a escribir
    mov     edx, [ebp+16]   ; tercer parametro, cantidad a escribir

    int     085h

    mov     esp, ebp        ; destruye stack frame
    pop     ebp
    ret

getChar:
    push    ebp
    mov     ebp, esp
    mov     eax, readCode
 
    int     086h

    mov     esp, ebp
    pop     ebp
    ret

shmGet:
    push    ebp
    mov     ebp, esp
    mov     eax, shmgetCode
    mov     ebx, [ebp+8]    ; key
    mov     ecx, [ebp+12]   ; size
    push    ecx
    push    ebx
    int     086h
    pop     ebx
    pop     ebx
    mov     esp, ebp
    pop     ebp
    ret

shmAt:
    push    ebp
    mov     ebp, esp
    mov     eax, shmatCode
    mov     ebx, [ebp+8]    ; id
    push    ebx
    int     086h
    pop     ebx
    mov     esp, ebp
    pop     ebp
    ret 

shmLock:
    push    ebp
    mov     ebp, esp
    mov     eax, shmlockCode
    mov     ebx, [ebp+8]
    push    ebx
    int     086h
    pop     ebx
    mov     esp, ebp
    pop     ebp
    ret

shmUnlock:
    push    ebp
    mov     ebp, esp
    mov     eax, shmUnlockCode
    mov     ebx, [ebp+8]
    push    ebx
    int     086h
    pop     ebx
    mov     esp, ebp
    pop     ebp
    ret

malloc:
    push    ebp
    mov     ebp, esp
    mov     eax, mallocCode
    mov     ebx, [ebp+8]    ; size
    push    ebx
    int     086h
    pop     ebx
    mov     esp, ebp
    pop     ebp
    ret

int_85_hand:
    cli                     ; Please don't disturb
    push    ds
    push    es
    pusha

    push    edx             ; Parametro 3
    push    ecx             ; Parametro 2
    push    ebx             ; Parametro 1
    push    eax             ; Codigo de operacion
    call    int_85

    pop     eax             ; quito los parametros de la pila
    pop     eax
    pop     eax
    pop     eax

    popa
    pop     es
    pop     ds
    sti
    iret



; _kill coloca en ebx el codigo de comando correspondiente y en
; ecx el pid a matar.
_kill:
    push    ebp             ; arma stack frame
    mov     ebp, esp

    mov     eax, killCode
    mov     ebx, [ebp+8]    ; pid

    int     085h

    mov     esp, ebp        ; destruye stack frame
    pop     ebp
    ret

; _renice coloca en ebx el codigo de comando correspondiente , en ecx el pid
; del proceso a alterar la prioridad y en edx la nueva prioridad.
_renice:
    push    ebp             ; arma stack frame
    mov     ebp, esp

    mov     eax, reniceCode
    mov     ebx, [ebp+8]    ; primer  parametro, pid
    mov     ecx, [ebp+12]   ; segundo parametro, prioridad nueva

    int     085h

    mov     esp, ebp        ; destruye stack frame
    pop     ebp
    ret


int_86_hand:
    cli                     ; Please don't disturb
    push    ds
    push    es

    push    ecx
    push    ebx
    push    eax             ; Codigo de operacion
    call    int_86

    pop     ebx
    pop     ebx
    pop     ebx
    pop     es
    pop     ds
    sti
    iret


ejecutar:
    push    ebp
    mov     ebp, esp

    mov     eax, ejecutarCode
    mov     ebx, [ebp+8]    ;nombre
    mov     ecx, [ebp+12]   ;funcion
    mov     edx, [ebp+16]   ;background
    
    int     085h
    
    mov     esp, ebp
    pop     ebp
    ret

int_09_hand:				; Handler de INT 9 (Teclado)
    cli
	push	ds
	push	es
	pusha
	mov     ax, 10h
	mov     ds, ax
	mov     es, ax
	in      al, 60h
	push	eax
	call	int_09
	mov     al, 20h
	out     20h, al
	pop     eax
	popa
	pop     es
	pop     ds
    sti
	iret

switch_manual:
    push ebp
    mov ebp, esp
    int 0x08
    mov esp, ebp
    pop ebp
    ret

; Debug para el BOCHS, detiene la ejecuci�n.
; Para continuar colocar en el BOCHSDBG: set $eax=0

debug:
    push    bp
    mov     bp, sp
    push	ax
vuelve:	
    mov     ax, 1
    cmp     ax, 0
	jne     vuelve
	pop     ax
	pop     bp
    retn
    
inb:		
	push ebp			
   	mov ebp, esp
	mov edx, [ebp+8]	; guarda el primer parametro en ebx
	mov eax, 0			; limpio eax
	in al, dx           ; escribe la data en al que esta en el puerto bx
	pop	ebp
	ret

outb:		
	push ebp		
    mov ebp, esp
	mov edx, [ebp+8]   ; guarda el primer parametro en ebx
	mov eax, [ebp+12]  ; guarda el segundo parametro en eax
	out dx, al		   ;  envia al puerto que esta en bx la data
	pop	ebp            
    ret	

[global read_cr0]
read_cr0:
	mov eax, cr0
	retn

[global write_cr0]
write_cr0:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr0,  eax
	pop ebp
	retn

[global read_cr3]
read_cr3:
	mov eax, cr3
	retn

[global write_cr3]
write_cr3:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr3, eax
	pop ebp
	retn

